﻿using System;
using ActiproSoftware.SyntaxEditor;
using ActiproSoftware.SyntaxEditor.Addons.Dynamic;

namespace LevenBlog.Core.CodeHighlighter {
    /// <summary>
    /// Provides an implementation of a <c>HTML</c> syntax language that can perform automatic outlining.
    /// </summary>
    public class HtmlDynamicSyntaxLanguage : DynamicOutliningSyntaxLanguage {

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // OBJECT
        /////////////////////////////////////////////////////////////////////////////////////////////////////

        /// <summary>
        /// This constructor is for designer use only and should never be called by your code.
        /// </summary>
        public HtmlDynamicSyntaxLanguage() {
        }
        //New

        /// <summary>
        /// Initializes a new instance of the <c>HtmlDynamicSyntaxLanguage</c> class. 
        /// </summary>
        /// <param name="key">The key of the language.</param>
        /// <param name="secure">Whether the language is secure.</param>
        public HtmlDynamicSyntaxLanguage(string key, bool secure)
            : base(key, secure) {
        }
        //New

        /////////////////////////////////////////////////////////////////////////////////////////////////////
        // PUBLIC PROCEDURES
        /////////////////////////////////////////////////////////////////////////////////////////////////////


        /// <summary>
        /// Returns token parsing information for automatic outlining that determines if the current <see cref="IToken"/>
        /// in the <see cref="TokenStream"/> starts or ends an outlining node.
        /// </summary>
        /// <param name="tokenStream">A <see cref="TokenStream"/> that is positioned at the <see cref="IToken"/> requiring outlining data.</param>
        /// <param name="outliningKey">Returns the outlining node key to assign. A <see langword="null"/> should be returned if the token doesn't start or end a node.</param>
        /// <param name="tokenAction">Returns the <see cref="OutliningNodeAction"/> to take for the token.</param>
        public override void GetTokenOutliningAction(TokenStream tokenStream, ref string outliningKey, ref OutliningNodeAction tokenAction) {
            // Get the token
            IToken token = tokenStream.Peek();
            string languageTokenKey = token.Language.Key + "_" + token.Key;

            // See if the token starts or ends an outlining node
            switch (languageTokenKey) {
                case "CSS_PropertyStartToken":
                    outliningKey = "CSS_PropertyBlock";
                    tokenAction = OutliningNodeAction.Start;
                    break;
                case "CSS_PropertyEndToken":
                    outliningKey = "CSS_PropertyBlock";
                    tokenAction = OutliningNodeAction.End;
                    break;
                case "CSS_CommentStartToken":
                    outliningKey = "CSS_Comment";
                    tokenAction = OutliningNodeAction.Start;
                    break;
                case "CSS_CommentEndToken":
                    outliningKey = "CSS_Comment";
                    tokenAction = OutliningNodeAction.End;
                    break;
                case "JScript_OpenCurlyBraceToken":
                    outliningKey = "JScript_CodeBlock";
                    tokenAction = OutliningNodeAction.Start;
                    break;
                case "JScript_CloseCurlyBraceToken":
                    outliningKey = "JScript_CodeBlock";
                    tokenAction = OutliningNodeAction.End;
                    break;
                case "JScript_MultiLineCommentStartToken":
                    outliningKey = "JScript_MultiLineComment";
                    tokenAction = OutliningNodeAction.Start;
                    break;
                case "JScript_MultiLineCommentEndToken":
                    outliningKey = "JScript_MultiLineComment";
                    tokenAction = OutliningNodeAction.End;
                    break;
                default:
                    // If a language change is occurring (tokenAction is only initialized to Start or End on language transitions)...
                    if (tokenAction != OutliningNodeAction.NoChange) {
                        if (token.HasFlag(LexicalParseFlags.LanguageStart)) {
                            if (tokenStream.Position > 0) {
                                IToken previousToken = tokenStream.ReadReverse();
                                if (previousToken.LexicalState.Key == "ASPDirectiveResponseWriteState") {
                                    // Don't do outlining on <%= %> blocks
                                    outliningKey = null;
                                    tokenAction = OutliningNodeAction.NoChange;
                                }
                            }
                        } else if (token.HasFlag(LexicalParseFlags.LanguageEnd)) {
                            tokenStream.Read();
                            if (!tokenStream.IsDocumentEnd) {
                                IToken nextToken = tokenStream.Peek();
                                if (nextToken.LexicalState.Key == "ASPDirectiveResponseWriteState") {
                                    // Don't do outlining on <%= %> blocks
                                    outliningKey = null;
                                    tokenAction = OutliningNodeAction.NoChange;
                                }
                            }
                        }
                    }

                    break;
            }
        }
        //GetTokenOutliningAction

        /// <summary>
        /// Allows for setting the collapsed text for the specified <see cref="OutliningNode"/>.
        /// </summary>
        /// <param name="node">The <see cref="OutliningNode"/> that is requesting collapsed text.</param>
        public override void SetOutliningNodeCollapsedText(OutliningNode node) {
            switch (node.ParseData.Key) {
                case "CSS_Comment":
                    node.CollapsedText = "/**/";
                    break;
                case "CSS_PropertyBlock":
                    node.CollapsedText = "{...}";
                    break;
                case "JScript_MultiLineComment":
                    node.CollapsedText = "/**/";
                    break;
            }
        }
        //SetOutliningNodeCollapsedText
    }
    //HtmlDynamicSyntaxLanguage
}
